/*
    日志器模块：对日志消息模块、日志等级模块、日志格式化模块、日志落地方向的整合
    1、抽象出日志器基类
    2、派生出不同子类(同步日志器&异步日志器)
 */
#ifndef __MY_LOGGER_H__
#define __MY_LOGGER_H__
#include "Util.hpp"
#include "Message.hpp"
#include "Lever.hpp"
#include "LogSink.hpp"
#include "Format.hpp"
#include "Buffer.hpp"
#include "Lopper.hpp"
#include <thread>
#include <atomic>
#include <mutex>
#include <vector>
#include <cstdarg>
#include <unordered_map>
namespace LogManager
{
    class Logger
    {
        /*
            1、管理日志格式化对象
            2、管理日志等级对象
            3、日志落地管理对象
            4、互斥锁
            5、日志器名称
        */
    public:
        using ptr = shared_ptr<Logger>;
        Logger(const string &logger_name,
               Format::Formatter::ptr format,
               Level::LogLevel::value level,
               vector<Sink::LogSink::ptr> sinks) : _logger_name(logger_name),
                                                   _format(format),
                                                   _limit_level(level),
                                                   _sinks(sinks.begin(), sinks.end()) {}
        const string &name() { return _logger_name; }
        // 提供不同的结构，组织出不同格式的输出字符串-----然后进行落地输出
        void log_info(const string &filename, size_t line, const string &fmt, ...)
        {
            // 1、判断当前日志是否达到输出等级
            if (Level::LogLevel::value::INFO < _limit_level)
                return;
            // 2、对fmt格式化字符串和不定参字符串进行组织，得到日志消息字符串
            va_list ap;
            va_start(ap, fmt); // 将ap指针指向fmt参数的下一个参数位置
            char *res;
            int ret = vasprintf(&res, fmt.c_str(), ap);
            va_end(ap);
            if (ret == -1)
            {
                cout << "vasprintf fail !!!" << endl;
                return;
            }
            Serialize(filename, line, res, Level::LogLevel::value::INFO);
            free(res);
        }
        void debug(const string &filename, size_t line, const string &fmt, ...)
        {
            // 1、判断当前日志是否达到输出等级
            if (Level::LogLevel::value::DEBUG < _limit_level)
                return;
            // 2、对fmt格式化字符串和不定参字符串进行组织，得到日志消息字符串
            va_list ap;
            va_start(ap, fmt); // 将ap指针指向fmt参数的下一个参数位置
            char *res;
            int ret = vasprintf(&res, fmt.c_str(), ap);
            va_end(ap);
            if (ret == -1)
            {
                cout << "vasprintf fail !!!" << endl;
                return;
            }
            Serialize(filename, line, res, Level::LogLevel::value::DEBUG);
            free(res);
        }
        void warn(const string &filename, size_t line, const string &fmt, ...)
        {
            // 1、判断当前日志是否达到输出等级
            if (Level::LogLevel::value::WARN < _limit_level)
                return;
            // 2、对fmt格式化字符串和不定参字符串进行组织，得到日志消息字符串
            va_list ap;
            va_start(ap, fmt); // 将ap指针指向fmt参数的下一个参数位置
            char *res;
            int ret = vasprintf(&res, fmt.c_str(), ap);
            va_end(ap);
            if (ret == -1)
            {
                cout << "vasprintf fail !!!" << endl;
                return;
            }
            Serialize(filename, line, res, Level::LogLevel::value::WARN);
            free(res);
        }
        void log_error(const string &filename, size_t line, const string &fmt, ...)
        {
            // 1、判断当前日志是否达到输出等级
            if (Level::LogLevel::value::ERROR < _limit_level)
                return;
            // 2、对fmt格式化字符串和不定参字符串进行组织，得到日志消息字符串
            va_list ap;
            va_start(ap, fmt); // 将ap指针指向fmt参数的下一个参数位置
            char *res;
            int ret = vasprintf(&res, fmt.c_str(), ap);
            va_end(ap);
            if (ret == -1)
            {
                cout << "vasprintf fail !!!" << endl;
                return;
            }
            Serialize(filename, line, res, Level::LogLevel::value::ERROR);
            free(res);
        }
        void fatal(const string &filename, size_t line, const string &fmt, ...)
        {
            // 1、判断当前日志是否达到输出等级
            if (Level::LogLevel::value::FATAL < _limit_level)
                return;
            // 2、对fmt格式化字符串和不定参字符串进行组织，得到日志消息字符串
            va_list ap;
            va_start(ap, fmt); // 将ap指针指向fmt参数的下一个参数位置
            char *res;
            int ret = vasprintf(&res, fmt.c_str(), ap);
            va_end(ap);
            if (ret == -1)
            {
                cout << "vasprintf fail !!!" << endl;
                return;
            }
            Serialize(filename, line, res, Level::LogLevel::value::FATAL);
            free(res);
        }

    protected:
        // 抽象接口负者完成实际落地输出-- 不同的日志器有不同的实际落地方式
        virtual void log(const string &Data, size_t len) = 0;

        void Serialize(const string &filename, size_t line, char *res, Level::LogLevel::value level)
        {
            // 3、构造LogMsg对象
            Message::LogMsg logmsg(filename, line, _logger_name, res, level);
            // 4、通过格式化对象中的接口进行格式化,得到格式化后的日志字符串
            stringstream ss;
            _format->format(ss, logmsg);
            // 5、日志落地
            log(ss.str(), ss.str().size());
        }

    protected:
        string _logger_name;                         // 日志器名称
        Format::Formatter::ptr _format;              // 日志格式化对象
        atomic<Level::LogLevel::value> _limit_level; // 日志器默认限制等级
        vector<Sink::LogSink::ptr> _sinks;           // 日志器落地对象
        mutex _mutex;
    };
    // 同步日志器 --直接将日志消息格式化落地
    class SynLogger : public Logger
    {
    public:
        SynLogger(const string &logger_name,
                  Format::Formatter::ptr format,
                  Level::LogLevel::value level,
                  vector<Sink::LogSink::ptr> sinks) : Logger(logger_name, format, level, sinks) {}
        void log(const string &Data, size_t len)
        {
            unique_lock<mutex> lock(_mutex);
            if (_sinks.empty())
                return;
            for (auto &sink : _sinks)
                sink->log(Data, len);
        }
    };
    // 异步日志器--将日志消息放入缓冲区，通过异步工作器完成对日志的落地
    class AsyncLogger : public Logger
    {
    public:
        AsyncLogger(const string &logger_name,
                    Format::Formatter::ptr format,
                    Level::LogLevel::value level,
                    Lopper::AsyncType type,
                    vector<Sink::LogSink::ptr> sinks)
            : Logger(logger_name, format, level, sinks),
              _lopper(make_shared<Lopper::AsyncLopper>(bind(&AsyncLogger::realLog, this, placeholders::_1), type)) {}
        // 将数据写入缓冲区
        void log(const string &Data, size_t len)
        {
            _lopper->push(Data.c_str(), len);
        }
        // 实际日志落地函数
        void realLog(LogBuffer::Buffer &buffer)
        {
            if (_sinks.empty())
                return;
            for (auto &sink : _sinks)
                sink->log(buffer.begin(), buffer.readAbleSize());
        }

    private:
        Lopper::AsyncLopper::ptr _lopper; // 定义一个异步工作器对象
    };
    enum class LoggerType
    {
        SYNC_Logger, // 同步日志器
        ASYNC_Logger // 异步日志器
    };

    // 使用建造者模式(完成对同步日志器*异步日志器)的构建
    /*
        1、设置日志器类型
        2、将不同的日志器类型放在同一个日志建造者类中完成
    */
    class LoggerBuilder
    {
    public:
        // 默认同步日志器，输出等级为debug,异步日志器类型默认为安全
        LoggerBuilder() : _logger_type(LoggerType::SYNC_Logger),
                          _limit_level(Level::LogLevel::value::DEBUG),
                          _lopper_type(Lopper::AsyncType::ASYNC_SAFE)
        {
        }
        void buildLoggerType(LoggerType type) { _logger_type = type; }
        void buildLoggerName(const string &name) { _logger_name = name; }
        void buildUnSafeLopperType() { _lopper_type = Lopper::AsyncType::ASYNC_UNSAFE; }
        void buildFormatter(const string &pattern)
        {
            _format = make_shared<Format::Formatter>(pattern);
        }
        void buildLoggerLevel(Level::LogLevel::value level) { _limit_level = level; }
        template <class SinkType, class... Args>
        void buildSink(Args &&...args)
        {
            _sinks.push_back(make_shared<SinkType>(std::forward<Args>(args)...));
        }
        virtual Logger::ptr build() = 0;

    protected:
        LoggerType _logger_type;
        Lopper::AsyncType _lopper_type;
        string _logger_name;
        Format::Formatter::ptr _format;
        Level::LogLevel::value _limit_level;
        vector<Sink::LogSink::ptr> _sinks;
    };
    // 2、派生出具体建造者类--(局部建造者&全局日志器建造者)
    class LocalLoggerBuilder : public LoggerBuilder
    {
    public:
        Logger::ptr build() override
        {
            assert(!_logger_name.empty()); // 必须传入日期器名称
            if (_format.get() == nullptr)
            {
                _format = make_shared<Format::Formatter>();
            } // 如果用户没有调用buildFormatter那就需要默认生产一个日志器格式化对象
            if (_sinks.empty())
            {
                buildSink<Sink::RollByTimeSink>("./logfile/roll-by-time-Async-", Sink::TimeGap::GAP_HOUR);
                //  buildSink<Sink::StdoutSink>(); // 没有传入落地方向，默认生成一个显示器落地方向
                // buildSink<Sink::RollBySizeSink>("./logfile/roll-by-size-Async-", 1024);
            }

            if (_logger_type == LoggerType::ASYNC_Logger)
            {
                return make_shared<AsyncLogger>(_logger_name, _format, _limit_level, _lopper_type, _sinks);
            }
            return make_shared<SynLogger>(_logger_name, _format, _limit_level, _sinks);
        }
    };

    // 采用单例模式,将所创建的日志器进行管理，程序可以在任意位置获得相同的单例对象，获取其中的日志器进行输出
    class LoggerManager
    {
    public:
        static LoggerManager &GetInstance()
        {
            static LoggerManager eton;
            return eton;
        }
        // 添加日志器
        void addLogger(Logger::ptr &logger)
        {
            // 判断日志器是否存在
            if (hasLogger(logger->name()))
                return;
            unique_lock<mutex> lock(_mutex);
            _loggers.insert({logger->name(), logger});
        }
        // 判断指定日志器是否存在
        bool hasLogger(const string &loggerName)
        {
            unique_lock<mutex> lock(_mutex);
            auto pos = _loggers.find(loggerName);
            if (pos == _loggers.end())
            {
                return false;
            }
            return true;
        }

        // 获取指定名称日志器
        Logger::ptr getLogger(const string &loggerName)
        {
            unique_lock<mutex> lock(_mutex);
            auto pos = _loggers.find(loggerName);
            if (pos == _loggers.end())
            {
                return Logger::ptr();
            }
            return pos->second;
        }
        // 获取默认日志器
        Logger::ptr get_rootLogger()
        {
            unique_lock<mutex> lock(_mutex);
            return _root_logger;
        }

    private:
        LoggerManager()
        {
            unique_ptr<LoggerBuilder> logger(new LocalLoggerBuilder());
            logger->buildLoggerName("root");
            _root_logger = logger->build();
            _loggers.insert({"root", _root_logger});
        }

    private:
        Logger::ptr _root_logger;                    // 默认日志器
        unordered_map<string, Logger::ptr> _loggers; // 日志器管理数组
        mutex _mutex;
    };

    class GlobalLoggerBuilder : public LoggerBuilder
    {
    public:
        Logger::ptr build() override
        {
            assert(!_logger_name.empty()); // 必须传入日期器名称
            if (_format.get() == nullptr)
            {
                _format = make_shared<Format::Formatter>();
            } // 如果用户没有调用buildFormatter那就需要默认生产一个日志器格式化对象
            if (_sinks.empty())
            {
                buildSink<Sink::StdoutSink>(); // 没有传入落地方向，默认生成一个显示器落地方向
            }
            Logger::ptr logger;
            if (_logger_type == LoggerType::ASYNC_Logger)
            {
                logger = make_shared<AsyncLogger>(_logger_name, _format, _limit_level, _lopper_type, _sinks);
            }
            else
            {
                logger = make_shared<SynLogger>(_logger_name, _format, _limit_level, _sinks);
            }
            LoggerManager::GetInstance().addLogger(logger);
            return logger;
        }
    };
}
#endif